
#include <QHostAddress>
#include <QDataStream>
#include <QString>
#include "../common/shogierror.h"
#include "../common/shogicommand.h"
#include "shogiserver.h"
#include "shogistate.h"

ShogiServer::ShogiServer()
{ 
	m_players[PLAYER_ONE] = new ShogiPlayer(PLAYER_ONE);
	m_players[PLAYER_TWO] = new ShogiPlayer(PLAYER_TWO);	
	
}

ShogiServer::~ShogiServer()
{
	delete m_players[PLAYER_ONE];
	delete m_players[PLAYER_TWO];
}

bool ShogiServer::start()
{
	bool bResult = false;
	
	connect(&m_listener,SIGNAL(newConnection()),this,SLOT(newPlayerConnected()));
	

	if (m_listener.listen(QHostAddress::Any,SERVER_PORT))
	{
		LOGSERVER("Started listening for incoming connections...");
		bResult = true;
	}
	else
	{		
		LOGSERVER("Failed to start the client listener!");			
		bResult = false;
	}

	return bResult;
}

void ShogiServer::playerChangedState(Player p)
{
	QString fmt;
	fmt.sprintf("*** Player %d changed internal state to %s",p+1,(const char*)getStateString(m_players[p]->getGameState()).toAscii());
	LOGSERVER(fmt);

	ShogiRegistry::instance()->getParent()->setPlayerState(p,m_players[p]->getGameState());
	// Here we do the checks to see if both players are in a state we're they are holding for the other player
	// Typically this could be WAIT_FOR_PLAYER or GAME_FINISHED

	// Chek for important states

	if(m_players[PLAYER_ONE]->getGameState() == WAIT_FOR_PLAYER && m_players[PLAYER_TWO]->getGameState() == WAIT_FOR_PLAYER)
	{
		emit signalForceStateChange(GAME_NEGOTIATION);

		ShogiCommand sendCmd(PLAYER_TWO);
		sendCmd.setCommand(g_CommandMappings[GAME_PARAM_WAIT].cmdString);
		sendCommand(PLAYER_TWO,sendCmd);

		ShogiCommand sendCmd2(PLAYER_ONE);
		sendCmd2.setCommand(g_CommandMappings[GAME_PARAM_START].cmdString);
		sendCommand(PLAYER_ONE,sendCmd2);
	}
	

}


void ShogiServer::playerWaitingForOtherPlayerToFinishState(Player p)
{
	if (m_players[PLAYER_ONE]->getStateObject()->getGameNegotiationTracker().checkFlag("game_params_accepted") && 
	    m_players[PLAYER_TWO]->getStateObject()->getGameNegotiationTracker().checkFlag("game_params_accepted"))
	{
		LOGSERVER("Both players have accepted the game parameters, lets switch state!");
		m_players[PLAYER_ONE]->getStateObject()->getGameNegotiationTracker().setFlag("game_negotiation_completed",true);
		m_players[PLAYER_TWO]->getStateObject()->getGameNegotiationTracker().setFlag("game_negotiation_completed",true);
		emit signalForceStateChange(IN_GAME);
	}
	else
	{
		LOGSERVER("One player has not yet accepted the game parameters...");
	}
}


void ShogiServer::newPlayerConnected()
{			
	if (!m_players[PLAYER_ONE]->hasSocketAssigned())
	{
		LOGSERVER("Player one has connected.");
		m_players[PLAYER_ONE]->assignSocket(m_listener.nextPendingConnection());
		connect(m_players[PLAYER_ONE]->getStateObject(),SIGNAL(signalStateChange(Player)),this,SLOT(playerChangedState(Player)));
		connect(this,SIGNAL(signalForceStateChange(GameState)),m_players[PLAYER_ONE],SLOT(forceStateChange(GameState)));
		
		connect(m_players[PLAYER_ONE]->getStateObject(),SIGNAL(signalReadyToSend(Player,ShogiCommand)),this,SLOT(sendCommand(Player,ShogiCommand)));
		connect(m_players[PLAYER_ONE]->getStateObject(),SIGNAL(signalWaitingForOtherPlayer(Player)),this,SLOT(playerWaitingForOtherPlayerToFinishState(Player)));

	}
	else if(!m_players[PLAYER_TWO]->hasSocketAssigned())
	{
		LOGSERVER("Player two has connected.");
		m_players[PLAYER_TWO]->assignSocket(m_listener.nextPendingConnection());
		connect(m_players[PLAYER_TWO]->getStateObject(),SIGNAL(signalStateChange(Player)),this,SLOT(playerChangedState(Player)));
		connect(this,SIGNAL(signalForceStateChange(GameState)),m_players[PLAYER_TWO],SLOT(forceStateChange(GameState)));
		connect(m_players[PLAYER_TWO]->getStateObject(),SIGNAL(signalReadyToSend(Player,ShogiCommand)),this,SLOT(sendCommand(Player,ShogiCommand)));
		connect(m_players[PLAYER_ONE]->getStateObject(),SIGNAL(signalWaitingForOtherPlayer(Player)),this,SLOT(playerWaitingForOtherPlayerToFinishState(Player)));
	}
	else
	{
		// TODO: Error - Both players already have sockets assigned. A third player?
		LOGSERVER("Error - Both players already have sockets assigned. A third player?");
	}
}

void ShogiServer::sendCommand(Player p, ShogiCommand cmd)
{
	LOGSERVER("sendCommand");

	if (m_players[p]->getSocket() != NULL && m_players[p]->getSocket()->state()== QAbstractSocket::ConnectedState)
	{
		QDataStream out(m_players[p]->getSocket());
		out.setVersion(QDataStream::Qt_4_0);
		out << cmd.getFullCommand();				
		LOGSERVER(QString("Server sent command ") + cmd.getFullCommand());
	}
	else
	{
		// TODO: Error could not send command
		LOGSERVER(QString("Server could not send command ") + cmd.getFullCommand());
	}
}